using System.Collections.Generic;
using System;
using Maki;
namespace Geometry
{
    public struct InterpolatedVertex
    {
        /**
         * @brief The index of the first vertex to interpolate between.
         */
        public int first;

        /**
         * @brief The index of the second vertex to interpolate between.
         */
        public int second;

        /**
         * @brief The fraction of the distance from {@link first} to {@link second} at
         * which to interpolate.
         */
        public double t;

        public InterpolatedVertex(int first, int second, double t)
        {
            this.first = first;
            this.second = second;
            this.t = t;
        }
        //   constexpr bool operator==(const InterpolatedVertex& other) const noexcept {
        //     return this->first == other.first && this->second == other.second &&
        //            std::fabs(this->t - other.t) <=
        //                std::numeric_limits<double>::epsilon();
        //   }

        //   constexpr bool operator!=(const InterpolatedVertex& other) const noexcept {
        //     return !(*this == other);
        //   }
    };

    public class clipTriangle
    {
        public static void clipTriangleAtAxisAlignedThreshold(
    double threshold,
    bool keepAbove,
    int i0,
    int i1,
    int i2,
    double u0,
    double u1,
    double u2,
    List<Variant<int, InterpolatedVertex>> result)
        {
            bool u0Behind, u1Behind, u2Behind;
            if (keepAbove)
            {
                u0Behind = u0 < threshold;
                u1Behind = u1 < threshold;
                u2Behind = u2 < threshold;
            }
            else
            {
                u0Behind = u0 > threshold;
                u1Behind = u1 > threshold;
                u2Behind = u2 > threshold;
            }

            int numberOfBehind = 0;
            numberOfBehind += u0Behind ? 1 : 0;
            numberOfBehind += u1Behind ? 1 : 0;
            numberOfBehind += u2Behind ? 1 : 0;

            double u01Ratio = 0.0;
            double u02Ratio = 0.0;
            double u12Ratio = 0.0;
            double u10Ratio = 0.0;
            double u20Ratio = 0.0;
            double u21Ratio = 0.0;
            if (numberOfBehind == 1)
            {
                if (u0Behind)
                {
                    u01Ratio = (threshold - u0) / (u1 - u0);
                    u02Ratio = (threshold - u0) / (u2 - u0);
                    result.Add(i1);
                    result.Add(i2);
                    if (u02Ratio != 1.0)
                    {
                        result.Add(new InterpolatedVertex(i0, i2, u02Ratio));
                    }
                    if (u01Ratio != 1.0)
                    {
                        result.Add(new InterpolatedVertex(i0, i1, u01Ratio));
                    }
                }
                else if (u1Behind)
                {
                    u12Ratio = (threshold - u1) / (u2 - u1);
                    u10Ratio = (threshold - u1) / (u0 - u1);
                    result.Add(i2);
                    result.Add(i0);
                    if (u10Ratio != 1.0)
                    {
                        result.Add(new InterpolatedVertex(i1, i0, u10Ratio));
                    }
                    if (u12Ratio != 1.0)
                    {
                        result.Add(new InterpolatedVertex(i1, i2, u12Ratio));
                    }
                }
                else if (u2Behind)
                {
                    u20Ratio = (threshold - u2) / (u0 - u2);
                    u21Ratio = (threshold - u2) / (u1 - u2);
                    result.Add(i0);
                    result.Add(i1);
                    if (u21Ratio != 1.0)
                    {
                        result.Add(new InterpolatedVertex(i2, i1, u21Ratio));
                    }
                    if (u20Ratio != 1.0)
                    {
                        result.Add(new InterpolatedVertex(i2, i0, u20Ratio));
                    }
                }
            }
            else if (numberOfBehind == 2)
            {
                if (!u0Behind && u0 != threshold)
                {
                    u10Ratio = (threshold - u1) / (u0 - u1);
                    u20Ratio = (threshold - u2) / (u0 - u2);
                    result.Add(i0);
                    result.Add(new InterpolatedVertex(i1, i0, u10Ratio));
                    result.Add(new InterpolatedVertex(i2, i0, u20Ratio));
                }
                else if (!u1Behind && u1 != threshold)
                {
                    u21Ratio = (threshold - u2) / (u1 - u2);
                    u01Ratio = (threshold - u0) / (u1 - u0);
                    result.Add(i1);
                    result.Add(new InterpolatedVertex(i2, i1, u21Ratio));
                    result.Add(new InterpolatedVertex(i0, i1, u01Ratio));
                }
                else if (!u2Behind && u2 != threshold)
                {
                    u02Ratio = (threshold - u0) / (u2 - u0);
                    u12Ratio = (threshold - u1) / (u2 - u1);
                    result.Add(i2);
                    result.Add(new InterpolatedVertex(i0, i2, u02Ratio));
                    result.Add(new InterpolatedVertex(i1, i2, u12Ratio));
                }
            }
            else if (numberOfBehind != 3)
            {
                // Completely in front of threshold
                result.Add(i0);
                result.Add(i1);
                result.Add(i2);
            }
        }
    }
}
